package net.sourceforge.peertwitter.scamp;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import rice.environment.Environment;
import rice.p2p.commonapi.Id;
import rice.p2p.commonapi.NodeHandle;


public class Swarm implements Iterable<NodeHandle>, Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 8234997935182684191L;
	private final Set<NodeHandle>followers = new HashSet<NodeHandle>();
	private final Id owner;
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((owner == null) ? 0 : owner.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		Swarm other = (Swarm) obj;
		if (owner == null) {
			if (other.owner != null) {
				return false;
			}
		} else if (!owner.equals(other.owner)) {
			return false;
		}
		return true;
	}

	private boolean enabled;
	private long date;
	private Environment env;

	public Swarm(Id owner, Environment env) {
		this.owner = owner;
		this.enabled = false;
		this.env = env;
		this.date = env.getTimeSource().currentTimeMillis();
	}
	
	public void addParticipant(NodeHandle follower) {
		followers.add(follower);
		this.date = -1;
	}
	
	public boolean removeParticipant(NodeHandle follower) {
		this.date = -1;
		return followers.remove(follower);
	}
	
	public void enable() {
		this.enabled = true;
	}
	
	public void disable() {
		this.enabled = false;
		this.followers.clear();
	}
	
	public boolean isEnabled() {
		return this.enabled;
	}

	@Override
	public Iterator<NodeHandle> iterator() {
		return followers.iterator();
	}

	public int size() {
		return followers.size();
	}

	public NodeHandle getRandomParticipant() {
		return followers.toArray(new NodeHandle[0])[env.getRandomSource().nextInt(size())];
	}
	
	public NodeHandle getRandomParticipant(NodeHandle except) {
		Set<NodeHandle> candidates = this.followers;
		if (candidates.contains(except)) {
			candidates = new HashSet<NodeHandle>(followers);
			candidates.remove(except);
		}
		if (candidates.isEmpty()) {
			throw new RuntimeException("No random participaint can be obtained, the empty is set.");
		}
		return candidates.toArray(new NodeHandle[0])[env.getRandomSource().nextInt(candidates.size())];
	}

	public boolean participates(NodeHandle follower) {
		return followers.contains(follower);
	}

	public boolean isEmpty() {
		return followers.isEmpty();
	}
	
	public Id getOwner() {
		return this.owner;
	}

	public long getDate() {
		return this.date;
	}
}
